<?php
/**
 * ValidatorModelExt.php class file.
 * @author wudg <544038230@qq.com>
 * @date 2020/10/21- 1:33 下午
 */
namespace common\components\ext;

use yii\base\DynamicModel;
use yii\base\UnknownPropertyException;
use yii\helpers\ArrayHelper;
use yii\validators\Validator;
use yii\base\InvalidConfigException;
use Yii;

/**
 * 复写参数校验model
 * Class ValidatorModelExt
 * @package taobao\components\ext
 */
class ValidatorModelExt extends DynamicModel
{
    /**
     * 属性标签
     *
     * @var array
     */
    private $_attributeLabels = [];


    /**
     *
     * {@inheritdoc}
     *
     * @param string $name
     * @return mixed|null
     * @throws \Exception
     */
    public function __get($name)
    {
        try {
            if (strpos($name, '.') !== false) {
                list($prefix, $key) = explode('.', $name, 2);
                if ($this->hasAttribute($prefix)) {
                    $array = parent::__get($prefix);
                    if (!is_array($array)) {
                        return null;
                    }
                    return ArrayHelper::getValue($array, $key);
                } else {
                    return parent::__get($name);
                }
            } else {
                return parent::__get($name);
            }
        } catch (UnknownPropertyException $e) {
            return null;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function __set($name, $value)
    {
        if (strpos($name, '.') !== false) {
            list($prefix, $key) = explode('.', $name, 2);
            if ($this->hasAttribute($prefix)) {
                $array = parent::__get($prefix);
                if (!is_array($array)) {
                    throw new UnknownPropertyException('Setting non array property: ' . get_class($this) . '::' . $name);
                }
                ArrayHelper::setValue($array, $key, $value);
                parent::__set($prefix, $array);
            } else {
                parent::__set($name, $value);
            }
        } else {
            parent::__set($name, $value);
        }
    }


    /**
     * @param array $data
     * @param array $rules
     * @param array $attributeLabels
     * @return DynamicModel
     * @throws InvalidConfigException
     */
    public static function validateData(array $data, $rules = [], $attributeLabels = [])
    {
        /* @var $model DynamicModel */
        $model = new static($data);
        if (!empty($rules)) {
            $validators = $model->getValidators();
            foreach ($rules as $rule) {
                if ($rule instanceof Validator) {
                    $validators->append($rule);
                } elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type
                    // 支持modelClassName对象自动获取attributeLabels属性标签
                    if (!empty($rule['modelClassName'])) {
                        $modelObj = Yii::createObject($rule['modelClassName']);
                        if (!empty($modelObj->attributeLabels())) {
                            $attributeLabels = array_merge($attributeLabels, $modelObj->attributeLabels());
                        }
                    }
                    unset($rule['modelClassName']); // 删除modelClassName避免校验器报错
                    $validator = Validator::createValidator($rule[1], $model, (array)$rule[0], array_slice($rule, 2));
                    $validators->append($validator);
                } else {
                    throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.');
                }
            }
        }
        $model->_attributeLabels = $attributeLabels; // 属性标签赋值

        $model->validate();

        return $model;
    }

    /**
     * 获取属性标签
     *
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return $this->_attributeLabels;
    }

}